﻿/*************************************************************************************
 * 文 件 名:   HK_SmartCopy
 * 
 * 描    述:   对选中的物体进行智能复制，按Ctrl+Shift+D进行复制（只能且必须选中一个物体），
 *             第一次复制时会记录便宜的位移、旋转、缩放，之后再次按Ctrl+Shift+D可根据偏移量增量连续进行复制
 *             借鉴Maya中的复制功能）
 * 
 * 版    本：  V1.1
 * 创 建 者：  京产肠饭
 * 创建时间：  2021/8/26
 * 链   接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using UnityEditor;
using UnityEngine;


[InitializeOnLoad]
public class HK_SmartCopy
{
    static HK_SmartCopy()
    {
        HK_ToolSetting.ChangeSmartCopyEvent += OnChangeSmartCopyEvent;
    }

    static void OnChangeSmartCopyEvent(bool _isEnable)
    {
        isEnable = _isEnable;
    }

    static bool isEnable = true;

    //执行的步骤
    static int moveStep = 0;

    //选中的第一个物体 初始位置、旋转、缩放
    static Vector3 startPos;
    static Vector3 startEuler;
    static Vector3 startScale;

    static Vector3 firstForward;
    static Vector3 firstRight;
    static Vector3 firstUp;

    //通过复制出来的第一个物体 计算出来的 偏移位置、旋转、缩放
    static Vector3 offsetPos;

    static Vector3 offsetX;
    static Vector3 offsetY;
    static Vector3 offsetZ;

    static float offsetXVal;
    static float offsetYVal;
    static float offsetZVal;

    static Vector3 offsetEuler;

    static float xScaleIndex;
    static float yScaleIndex;
    static float zScaleIndex;

    //记录上一个复制的 位置和旋转
    static Vector3 lastPos;
    static Quaternion lastRotation;
    static Vector3 lastScale;

    static Transform parentTF = null;
    static GameObject lastSelectGo = null;
    static GameObject selectGo = null;

    [MenuItem("HKTools/SmartCopy %#D", true, 11)]
    static bool CopyObjValidate()
    {
        return isEnable;
    }

    [MenuItem("HKTools/SmartCopy %#D", false, 11)]
    static void CopyObj()
    {
        if (!isEnable) return;

        // 判断是否只选中了一个物体 
        if (Selection.gameObjects.Length > 1)
        {
            Debug.Log("<color=red>错误:只能选择一个Hierarchy中的物体进行复制</color>");
            return;
        }
        if (Selection.gameObjects.Length == 0)
        {
            Debug.Log("<color=red>错误:未选中物体，无法执行复制操作</color>");
            return;
        }

        if (moveStep == 0)    // 第一步： 记录是否有 Parent ，Copy选中物体 ，记录第一个物体 三个轴向 和 初始位置旋转
        {
            //如果选中物体有父物体 ，则脱离父物体
            if (Selection.activeGameObject.transform.parent != null)
            {
                parentTF = Selection.activeGameObject.transform.parent;
                Selection.activeGameObject.transform.parent = null;
            }
            else
            {
                parentTF = null;
            }

            lastSelectGo = Selection.activeGameObject;

            EditorApplication.ExecuteMenuItem("Edit/Duplicate");

            if (parentTF != null)
                lastSelectGo.transform.SetParent(parentTF);

            //记录第一个物体的 三个轴向 & 开始的 位置和旋转
            firstForward = Selection.activeGameObject.transform.forward;
            firstRight = Selection.activeGameObject.transform.right;
            firstUp = Selection.activeGameObject.transform.up;

            startPos = Selection.activeGameObject.transform.position;
            startEuler = Selection.activeGameObject.transform.eulerAngles;

            startScale = Selection.activeGameObject.transform.localScale;

            selectGo = Selection.activeGameObject;

            if (parentTF != null)
                selectGo.transform.SetParent(parentTF);

            moveStep++;
        }
        else if (moveStep == 1)   // 第二步 ： 判定 偏移向量 在各个轴向的分量，并复制
        {
            if (Selection.activeGameObject != selectGo)
            {
                moveStep = 0;
                CopyObj();
                return;
            }

            //如果选中物体 位置与旋转 并没发生改变 ，则返回第一步
            if (Selection.activeGameObject.transform.position == startPos && Selection.activeGameObject.transform.eulerAngles == startEuler && Selection.activeGameObject.transform.localScale == startScale)
            {
                moveStep = 0;
                CopyObj();
                return;
            }
            else
            {
                parentTF = null;
            }

            //如果 选中物体 有父物体 ， 则脱离父物体
            if (Selection.activeGameObject.transform.parent != null)
            {
                parentTF = Selection.activeGameObject.transform.parent;
                Selection.activeGameObject.transform.parent = null;
            }

            //计算便宜的向量 和 每个轴向的分量
            offsetPos = Selection.activeGameObject.transform.position - startPos;

            offsetX = Vector3.Project(offsetPos, firstRight);
            offsetY = Vector3.Project(offsetPos, firstUp);
            offsetZ = Vector3.Project(offsetPos, firstForward);

            if (Vector3.Dot(firstRight.normalized, offsetX.normalized) > 0)
                offsetXVal = offsetX.magnitude;
            else
                offsetXVal = -offsetX.magnitude;
            if (Vector3.Dot(firstForward.normalized, offsetZ.normalized) < 0)
                offsetZVal = -offsetZ.magnitude;
            else
                offsetZVal = offsetZ.magnitude;
            if (Vector3.Dot(firstUp.normalized, offsetY.normalized) < 0)
                offsetYVal = -offsetY.magnitude;
            else
                offsetYVal = offsetY.magnitude;

            offsetEuler = Selection.activeGameObject.transform.eulerAngles - startEuler;

            lastSelectGo = Selection.activeGameObject;

            EditorApplication.ExecuteMenuItem("Edit/Duplicate");

            if (parentTF != null)
                lastSelectGo.transform.SetParent(parentTF);

            Selection.activeGameObject.transform.Translate(offsetXVal, offsetYVal, offsetZVal, Space.Self);
            Selection.activeGameObject.transform.eulerAngles = Selection.activeGameObject.transform.eulerAngles + offsetEuler;

            lastPos = Selection.activeGameObject.transform.position;
            lastRotation = Selection.activeGameObject.transform.rotation;

            if (parentTF != null)
                Selection.activeGameObject.transform.parent = parentTF;

            xScaleIndex = Selection.activeGameObject.transform.localScale.x / startScale.x;
            yScaleIndex = Selection.activeGameObject.transform.localScale.y / startScale.y;
            zScaleIndex = Selection.activeGameObject.transform.localScale.z / startScale.z;

            float x = Selection.activeGameObject.transform.localScale.x * xScaleIndex;

            float y = Selection.activeGameObject.transform.localScale.y * yScaleIndex;

            float z = Selection.activeGameObject.transform.localScale.z * zScaleIndex;

            Selection.activeGameObject.transform.localScale = new Vector3(x, y, z);

            lastScale = Selection.activeGameObject.transform.localScale;

            selectGo = Selection.activeGameObject;

            if (parentTF != null)
                selectGo.transform.SetParent(parentTF);

            moveStep++;
        }
        else if (moveStep == 2 && Selection.gameObjects.Length == 1)   // 第三步：就是一直复制呗
        {
            if (Selection.activeGameObject != selectGo)
            {
                moveStep = 0;
                CopyObj();
                return;
            }

            if (Vector3.Distance(Selection.activeGameObject.transform.position, lastPos) > 0.01f
                || Quaternion.Angle(Selection.activeGameObject.transform.rotation, lastRotation) > 0.1f
                || Vector3.Distance(Selection.activeGameObject.transform.localScale, lastScale) > 0.01f)
            {
                Debug.Log("重新复制");
                moveStep = 0;
                CopyObj();
                return;
            }
            else
            {
                parentTF = null;
            }

            //如果 选中物体 有父物体 ， 则脱离父物体
            if (Selection.activeGameObject.transform.parent != null)
            {
                parentTF = Selection.activeGameObject.transform.parent;
                Selection.activeGameObject.transform.parent = null;
            }

            lastSelectGo = Selection.activeGameObject;

            EditorApplication.ExecuteMenuItem("Edit/Duplicate");

            if (parentTF != null)
                lastSelectGo.transform.SetParent(parentTF);

            Selection.activeGameObject.transform.Translate(offsetXVal, offsetYVal, offsetZVal, Space.Self);
            Selection.activeGameObject.transform.eulerAngles = Selection.activeGameObject.transform.eulerAngles + offsetEuler;

            lastPos = Selection.activeGameObject.transform.position;
            lastRotation = Selection.activeGameObject.transform.rotation;

            if (parentTF != null)
                Selection.activeGameObject.transform.parent = parentTF;

            float x = Selection.activeGameObject.transform.localScale.x * xScaleIndex;

            float y = Selection.activeGameObject.transform.localScale.y * yScaleIndex;

            float z = Selection.activeGameObject.transform.localScale.z * zScaleIndex;

            Selection.activeGameObject.transform.localScale = new Vector3(x, y, z);

            lastScale = Selection.activeGameObject.transform.localScale;

            selectGo = Selection.activeGameObject;

            if (parentTF != null)
                selectGo.transform.SetParent(parentTF);
        }
    }
}
